package com.mew.slots.core.common.service;

import com.mew.common.dc.redis.AucRedisService;
import com.mew.common.dc.redis.GameRoomRedisService;
import com.mew.common.dc.redis.UserProfileRedisService;
import com.mew.common.enm.DataStateType;
import com.mew.common.enm.ExitType;
import com.mew.common.enm.SlotsPersistType;
import com.mew.common.enm.SlotsWinType;
import com.mew.common.entity.config.Room;
import com.mew.common.entity.game.Jackport;
import com.mew.common.entity.game.WinFree;
import com.mew.common.exception.ResponseCode;
import com.mew.common.rest.bo.GameSession;
import com.mew.common.rest.bo.MaxBonusBO;
import com.mew.common.rest.bo.MaxBonusManager;
import com.mew.common.rest.game.BetAfterRequest;
import com.mew.common.rest.game.BetBeforeRequest;
import com.mew.common.rest.game.BetBeforeResponse;
import com.mew.slots.core.common.handler.RoomBO;
import com.mew.slots.core.common.handler.RoomInfoManager;
import com.mew.slots.core.common.handler.SlotsSessionManager;
import com.mew.slots.core.common.handler.StrategyConfig;
import com.mew.slots.core.common.messge.request.BetRequestMessage;
import com.mew.slots.core.common.messge.request.BonusRequestMessage;
import com.mew.slots.core.common.messge.response.SlotsBonusPlayResponseMessage;
import com.mew.slots.core.common.messge.response.SlotsPlayResponseMessage;
import com.mew.slots.core.common.provide.GameFeignService;
import com.mew.slots.core.common.utils.SlotsPushMessageUtil;
import com.mew.slots.core.common.vo.StrategyGameVO;
import com.zebra.common.OnlineType;
import com.zebra.common.concurrent.ZebraExecutorManager;
import com.zebra.remoting.config.BasisCommandCode;
import com.zebra.remoting.config.EmptyMessage;
import com.zebra.remoting.config.StateCode;
import com.zebra.remoting.config.TmsServerInfo;
import com.zebra.remoting.tms.TmsConfigInfoManager;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class BetService {
    private final Logger PLAY_INFO =  LoggerFactory.getLogger("PLAY_INFO");
    @Autowired
    private GameFeignService gameFeignService;
    @Autowired
    private UserProfileRedisService userProfileRedisService;
    @Autowired
    private GameRoomRedisService gameRoomRedisService;
    @Autowired
    private StrategyConfig strategyConfig;
    @Autowired
    private AucRedisService aucRedisService;

    @Autowired
    private SlotsSessionManager slotsSessionManager;


    public StrategyGameVO commonCheck(BetRequestMessage requestMessage, GameSession userVO){
        TmsServerInfo tmsServerInfo = TmsConfigInfoManager.getInstance().getServerInfo();
        if (tmsServerInfo.getOnline() < OnlineType.Online.value()){
            log.error("*****Slots Bet TMS not online {}", tmsServerInfo.toString());
            SlotsPushMessageUtil.pushMessage(userVO, BasisCommandCode.OVERHAULED.cmd(), new EmptyMessage((byte) 0));

            gameFeignService.exitRoom(userVO.getUserId(), ExitType.Exit.code());
            slotsSessionManager.remove(userVO.getUserId());
            aucRedisService.offlineSession(userVO.getUserId());

            return StrategyGameVO.builder().stat(ResponseCode.GameServerNotConfig.code()).build();
        }

        if (userVO.getWhiteList() == 0){
            Room room = gameRoomRedisService.getRedisRoom(userVO.getGameId(), userVO.getRoomId());
            if (null == room || DataStateType.Delete.code() == room.getState()){
                log.error("*****Slots Bet Room close gameId {} roomId {}", userVO.getGameId(), userVO.getRoomId());
                SlotsPushMessageUtil.pushMessage(userVO, BasisCommandCode.OVERHAULED.cmd(), new EmptyMessage((byte) 1));

                gameFeignService.exitRoom(userVO.getUserId(), ExitType.Exit.code());
                slotsSessionManager.remove(userVO.getUserId());
                return StrategyGameVO.builder().stat(ResponseCode.GameServerNotConfig.code()).build();
            }

            if (aucRedisService.getMaintenance()){
                log.error("*****SYS maintenance gameId {} roomId {}", userVO.getGameId(), userVO.getRoomId());
                SlotsPushMessageUtil.pushMessage(userVO, BasisCommandCode.OVERHAULED.cmd(), new EmptyMessage((byte) 0));

                gameFeignService.exitRoom(userVO.getUserId(), ExitType.Exit.code());
                slotsSessionManager.remove(userVO.getUserId());
                return StrategyGameVO.builder().stat(ResponseCode.GameServerNotConfig.code()).build();
            }
        }


        RoomBO roomBO = RoomInfoManager.getInstance().get(userVO.getRoomId());
        //验证压注 是否在压注区间内
        if (!roomBO.getBetStr().contains(String.valueOf(requestMessage.getBetNumber()))){
            return StrategyGameVO.builder().stat(ResponseCode.BetError.code()).build();
        }

        WinFree winFree = userProfileRedisService.getRedisWinfree(userVO.getUserId(), userVO.getRoomId());
        //判断这句是不是普通游戏 押注金币验证用
       if(winFree.getFrees()==0
                &&winFree.getBounsNumber()==0
                &&winFree.getBounsChange()==0){
           if(requestMessage.getBetNumber() * roomBO.getLineNumber()> userVO.getGoldNumber()){
               return StrategyGameVO.builder().stat(ResponseCode.GoldNo.code()).build();
           }
       }

        return StrategyGameVO.builder()
                .stat(ResponseCode.Success.code())
                .userId(userVO.getUserId())
                .roomId(userVO.getRoomId())
                .inBetNumber(requestMessage.getBetNumber())
                .otherMsg(requestMessage.getOtherMsg())
                .winFree(winFree)
                .minBetNumber(roomBO.getMinBet())
                .maxBetNumber(roomBO.getMaxBet())
                .lineNumber(roomBO.getLineNumber())
                .build();
    }


    public StrategyGameVO commonBonusCheck(BonusRequestMessage requestMessage, GameSession userVO){
        RoomBO roomBO = RoomInfoManager.getInstance().get(userVO.getRoomId());
        WinFree winFree = userProfileRedisService.getRedisWinfree(userVO.getUserId(), userVO.getRoomId());
        //Build StrategyGameVO
        return StrategyGameVO.builder()
                .stat(ResponseCode.Success.code())
                .userId(userVO.getUserId())
                .roomId(userVO.getRoomId())
                .bonusType(requestMessage.getBounsType())
                .otherMsg(requestMessage.getOtherMsg())
                .winFree(winFree)
                .minBetNumber(roomBO.getMinBet())
                .maxBetNumber(roomBO.getMaxBet())
                .lineNumber(roomBO.getLineNumber())
                .build();
    }

    /**
     * 押注前处理逻辑
     * @return
     */
    public void betBefore(StrategyGameVO gameVO, GameSession userVO){
        gameVO.setWinProb(50);
        gameVO.setRollerId(5);
    }

    /**
     * 游戏根据轴 出完图 等信息调用
     * @param gameVO
     * @return
     */
    public void bonusAfter(StrategyGameVO gameVO, GameSession userVO, SlotsBonusPlayResponseMessage message){
        jackPort(gameVO,userVO.getRoomId(),message);
        userVO.updateGoldNumber(gameVO.getBetNumber(), gameVO.getPaymentNumber());  //  ------本地缓存----------
        message.setGoldNumber(userVO.getGoldNumber());
        message.setBonusType(gameVO.getBonusType());
        //message.setExpProb(null == levelVO ? -1 : levelVO.expPercent());
        after(gameVO, userVO);
    }

    /**
     * 游戏根据轴 出完图 等信息调用
     * @param gameVO
     * @return
     */
    public void betAfter(StrategyGameVO gameVO, GameSession userVO, SlotsPlayResponseMessage message){
        jackPort(gameVO,userVO.getRoomId(),message);
        userVO.updateGoldNumber(gameVO.getBetNumber(), gameVO.getPaymentNumber());  //  ------本地缓存----------
        message.setGoldNumber(userVO.getGoldNumber());
        after(gameVO, userVO);
    }

    private void after(StrategyGameVO gameVO, GameSession userVO){
        userProfileRedisService.updateRedisWinfree(gameVO.getWinFree());
        doMaxBonus(userVO.getUserId(), userVO.getGameId(), gameVO.getPaymentNumber(), gameVO.getBetTimes());

        //----****--需要回写的数据 才调用回写
        if (gameVO.getNotRecord() == SlotsPersistType.ALL.code()){
            ZebraExecutorManager.getInstance().getDefaultExecutor().execute(()->{
                BetAfterRequest request = BetAfterRequest.builder()
                        .uid(userVO.getUserId())
                        .relateInoutId(userVO.getInoutId())
                        .gameId(userVO.getGameId())
                        .roomId(userVO.getRoomId())
                        .bet(gameVO.getBetNumber())
                        .payment(gameVO.getPaymentNumber())
                        .rollerId(gameVO.getRollerId())
                        .roomRecord(gameVO.getRoomRecord())
                        .winType(gameVO.getWinType())
                        .betTimes(gameVO.getBetTimes())
                        .iconResult(gameVO.getIconResult())
                        .special(gameVO.isSpecial())
                        .build();
                gameFeignService.betAfter(request);
            });
        }
    }

    private void doMaxBonus(long userId, int gameId, long payment, int betTimes){
        if (betTimes < 50){
            return;
        }

        if (payment >= strategyConfig.goldMax() && betTimes >= strategyConfig.getSlotsMul()){
           MaxBonusBO maxBonusBO = MaxBonusBO.builder()
                    .un(userProfileRedisService.getRedisUserById(userId).getNickname())
                    .gn(gameRoomRedisService.getRedisGame(gameId).getForeignLag())
                    .num(payment)
                    .build();
            MaxBonusManager.getInstance().add(maxBonusBO);
        }
    }

    private void jackPort(StrategyGameVO gameVO,int roomId, SlotsPlayResponseMessage message){
        long jp = disposeJackpot(gameVO,roomId, message.getJpNo());
        message.setJp(jp);
        message.setJpNo(message.getJpNo());
    }
    private void jackPort(StrategyGameVO gameVO, int roomId, SlotsBonusPlayResponseMessage message){
        long jp = disposeJackpot(gameVO,roomId, message.getJpNo());
        message.setJp(jp);
        message.setJpNo(message.getJpNo());
    }

    private long disposeJackpot(StrategyGameVO gameVO, int roomId,int jpNo){
        if(gameVO.getWinType()==SlotsWinType.Jackpot.code()&&jpNo>0){
            Jackport jackport =gameRoomRedisService.findJackPortOne(roomId,jpNo);
            if(null==jackport){
                return 0l;
            }
            long jp=(long)(0.3*gameVO.getWinFree().getBet()/gameVO.getMaxBetNumber()*jackport.getVal());

            gameVO.setPaymentNumber(gameVO.getPaymentNumber()+jp);

            //更新奖池值
            jackport.setVal(jackport.getVal()-jp);
            gameRoomRedisService.updateJackPort(roomId,jackport);
/*            gameFeignService.ujp(jackport);*/
            return jp;
        }
        return 0l;
    }
    public void log(StrategyGameVO gameVO,GameSession gameSession){
        PLAY_INFO.info(new SlotsLog().builderSlotsLog(gameVO,gameSession).toString());
    }
    @Data
    @ToString
    private class SlotsLog{
        private int gameId;
        private String vfx;
        private int roomId;
        private long userId;
        private long bet;
        private long payment;
        private String endSlots;
        private int winType;
        SlotsLog builderSlotsLog(StrategyGameVO gameVO,GameSession gameSession){
            this.gameId=gameSession.getGameId();
            this.vfx=gameSession.getVfx();
            this.roomId=gameSession.getRoomId();
            this.userId=gameVO.getUserId();
            this.bet=gameVO.getBetNumber()*gameVO.getLineNumber();
            this.payment=gameVO.getPaymentNumber();
            this.endSlots=gameVO.getIconResult();
            this.winType=gameVO.getWinType();
            return this;
        }
    }
}
